package com.stox.client.ui.javafx.chartingy.model.shape;

import javafx.beans.property.DoubleProperty;
import javafx.beans.property.LongProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleLongProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.EventHandler;
import javafx.geometry.Point2D;
import javafx.scene.input.MouseEvent;
import javafx.scene.shape.Circle;

import com.stox.client.ui.javafx.chartingy.model.chart.Chart;
import com.stox.client.ui.javafx.core.util.CSS;
import com.stox.client.ui.javafx.core.util.UI;

public class ControlPoint extends Circle {

	private double x = 0;
	private double y = 0;
	private final Chart<?, ?> chart;
	private final DoubleProperty priceProperty = new SimpleDoubleProperty(0);
	private final LongProperty dateProperty = new SimpleLongProperty(0);

	public ControlPoint(final Chart<?, ?> chart, final double initialSceneX, final double initialSceneY) {
		this(chart);
		x = initialSceneX;
		y = initialSceneY;
		final Point2D point = chart.getChartContentArea().sceneToLocal(initialSceneX, initialSceneY);
		setCenterX(point.getX());
		setCenterY(point.getY());
	}

	public ControlPoint(final Chart<?, ?> chart) {
		super(5);
		this.chart = chart;
		UI.style(this, CSS.controlPoint);

		setOnMousePressed(new EventHandler<MouseEvent>() {
			@Override
			public void handle(final MouseEvent event) {
				x = event.getSceneX();
				y = event.getSceneY();
				event.consume();
			}
		});

		addEventFilter(MouseEvent.MOUSE_DRAGGED, new EventHandler<MouseEvent>() {
			@Override
			public void handle(final MouseEvent event) {
				dragToX(event.getSceneX());
				dragToY(event.getSceneY());
				event.consume();
			}
		});

		centerXProperty().addListener(new ChangeListener<Number>() {
			@Override
			public void changed(final ObservableValue<? extends Number> observable, final Number oldValue, final Number newValue) {
				final long date = chart.getChartingView().getPrimaryChart().getDateAxis().getValueForDisplay(newValue.doubleValue());
				dateProperty.set(date);
			}
		});

		centerYProperty().addListener(new ChangeListener<Number>() {
			@Override
			public void changed(final ObservableValue<? extends Number> observable, final Number oldValue, final Number newValue) {
				final double price = chart.getValueAxis().getValueForDisplay(newValue.doubleValue());
				priceProperty.set(price);
			}
		});

	}

	protected void dragToY(final double sceneY) {
		final double delta = sceneY - y;
		setCenterY(getCenterY() + delta);
		y = sceneY;
	}

	protected void dragToX(final double sceneX) {
		final double delta = sceneX - x;
		setCenterX(getCenterX() + delta);
		x = sceneX;
	}

	public void update() {
		setCenterX(chart.getChartingView().getPrimaryChart().getDateAxis().getDisplayPosition(dateProperty.get()));
		setCenterY(chart.getValueAxis().getDisplayPosition(priceProperty.get()));
	}


	public Chart<?, ?> getChart() {
		return chart;
	}

	public LongProperty dateProperty() {
		return dateProperty;
	}

	public long getDate() {
		return dateProperty.get();
	}

	public void setDate(final long date) {
		dateProperty.set(date);
	}

	public DoubleProperty priceProperty() {
		return priceProperty;
	}

	public double getPrice() {
		return priceProperty.get();
	}

	public void setPrice(final double price) {
		priceProperty.set(price);
	}

}
